/*
 *  entity.cc
 *  wonderland-project
 *
 *  Created by Ben Nolan on 16/10/08.
 *  Copyright 2008 Nolan Consulting Limited. All rights reserved.
 *
 */

#include "entity.h"

#include <v8.h>
#include <Ogre.h>
#include "node.h"
#include "vector.h"
#include "quaternion.h"
#include "v8defines.h"
#include "scripting_context.h"
#include "skeleton.h"
#include "animation.h"

namespace JSEntity{
  
  v8::Handle<v8::ObjectTemplate> instance_template;
  v8::Handle<v8::FunctionTemplate> function_template;
  v8::Persistent<v8::Context> context_;

  V8_GETTER(Entity, id){
    return v8::String::New(V8INTERNAL(Ogre::Entity*)->getName().c_str());
  }

  V8_GETTER(Entity,animations){ 
	if(!V8INTERNAL(Ogre::Entity*)->getMesh()->hasSkeleton()){
		return v8::Array::New(0);
	}

	Ogre::SkeletonPtr skel = V8INTERNAL(Ogre::Entity*)->getMesh()->getSkeleton();
    
    int children = skel->getNumAnimations();
    v8::Handle<v8::Array> result_array = v8::Array::New(children); 

    for(int i=0;i<children;i++){
      result_array->Set(v8::Number::New(i), JSAnimation::New(
        V8INTERNAL(Ogre::Entity*)->getAnimationState(skel->getAnimation(i)->getName())
      ));
    }
    
    return result_array;
  }

  V8_GETTER(Entity,skeleton){
	if(!V8INTERNAL(Ogre::Entity*)->getMesh()->hasSkeleton()){
		return v8::Null();
	}
  
    return JSSkeleton::New(V8INTERNAL(Ogre::Entity*)->getSkeleton());
  }

  /* Get the size of the bounding box of the mesh in this entity */
  V8CALLBACK(Entity,getSize){
    return JSVector::New(V8INTERNAL(Ogre::Entity*)->getMesh()->getBounds().getSize());
  }

  /* Set a material */
  V8CALLBACK(Entity,setMaterial){
	if (args.Length() != 1){
		return v8::Undefined();
	}

	v8::String::Utf8Value name(args[0]);
	
    V8INTERNAL(Ogre::Entity*)->setMaterialName(*name);
	
	return v8::Undefined();
  }

  /* Not called directly - use world.createEntity */
  V8CALLBACK(Entity,create){
    v8::Persistent<v8::Object> self = v8::Persistent<v8::Object>::New(args.Holder());
    return self;
  }

  /* Sets internal fields with our idiom of storing the class name in the second field */
  void setInternalFields(v8::Persistent<v8::Object> p, Ogre::Entity *entity){
    p->SetInternalField(0, v8::External::New(entity));
    p->SetInternalField(1, v8::String::New("Entity"));
  }

  /* Only called from c++ */
  v8::Handle<v8::Value> New(Ogre::Entity *ent){
    
    context_->Enter();

    v8::Persistent<v8::Object> instance = v8::Persistent<v8::Object>::New(function_template->GetFunction()->NewInstance());
    setInternalFields(instance, ent);
    return instance;
  }

  void Initialize(Wonderland::ScriptingContext *sc){
    context_ = sc->getContext();

    // Function Template
    function_template = v8::FunctionTemplate::New(Entity_create);
    function_template->SetClassName(v8::String::New("Entity"));

    // Instance template
    instance_template = function_template->InstanceTemplate();
    instance_template->SetInternalFieldCount(2);

    #define V8REGISTER(function) instance_template->Set(#function, v8::FunctionTemplate::New(Entity_ ## function));
    
    instance_template->SetAccessor(v8::String::New("id"), Entity_getid);
    instance_template->SetAccessor(v8::String::New("skeleton"), Entity_getskeleton);
    instance_template->SetAccessor(v8::String::New("animations"), Entity_getanimations);

//    V8REGISTER(getAnimationNames);
    V8REGISTER(getSize);
    V8REGISTER(setMaterial);
  }

}

